/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.scrumpmt.web;

import java.text.DateFormat;
import java.text.ParseException;
import java.util.*;
import java.util.logging.Level;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.scrumpmt.domain.Colaborador;
import org.scrumpmt.domain.Esfuerzo;
import org.scrumpmt.domain.Sprint;
import org.scrumpmt.ejb.EsfuerzoFacade;
import org.scrumpmt.ejb.SprintFacade;
import org.scrumpmt.ejb.TareaFacade;
import org.scrumpmt.domain.Tarea;
import org.scrumpmt.ejb.ColaboradorFacade;

/**
 *
 * @author Cristian
 */
@ManagedBean(name = "estadistica")
@RequestScoped
public class estadistica extends BasicBean {

    private ColaboradorFacade colaboradorFacade = lookupColaboradorFacade();
    private SprintFacade sprintFacade = lookupSprintFacade();
    private TareaFacade tareaFacade = lookupTareaFacade();
    private EsfuerzoFacade esfuerzoFacade = lookupEsfuerzoFacade();
    private int relacion;
    private int duracion;
    private int totalEsfuerzo;
    private int actual[] = new int[]{};
    private int estimado[] = new int[]{};
    private int todo;
    private int doing;
    HashMap<String, int[]> mapaColaboradores = new HashMap<String, int[]>();
    ProductoSeleccionadoBean bean = null;
    private String sprintId;
    private String productoId;

    public String getProductoId() {
        return productoId;
    }

    public void setProductoId(String productoId) {
        this.productoId = productoId;
    }

    public String getSprintId() {
        return sprintId;
    }

    public void setSprintId(String sprintId) {
        this.sprintId = sprintId;
    }

    public ColaboradorFacade getColaboradorFacade() {
        return colaboradorFacade;
    }

    public HashMap<String, int[]> getMapaColaboradores() {
        return mapaColaboradores;
    }

    public int getDoing() {
        return doing;
    }

    public void setDoing(int doing) {
        this.doing = doing;
    }

    public int getDone() {
        return done;
    }

    public void setDone(int done) {
        this.done = done;
    }

    public int getTodo() {
        return todo;
    }

    public void setTodo(int todo) {
        this.todo = todo;
    }
    private int done;

    public int[] getActual() {
        return actual;
    }

    public void setActual(int[] actual) {
        this.actual = actual;
    }

    public int[] getEstimado() {
        return estimado;
    }

    public void setEstimado(int[] estimado) {
        this.estimado = estimado;
    }

    public int getTotalEsfuerzo() {
        return totalEsfuerzo;
    }

    public void setTotalEsfuerzo(int totalEsfuerzo) {
        this.totalEsfuerzo = totalEsfuerzo;
    }

    public int getRelacion() {
        return relacion;
    }

    public void setRelacion(int relacion) {
        this.relacion = relacion;
    }

    public int getDuracion() {
        return duracion;
    }

    public void setDuracion(int duracion) {
        this.duracion = duracion;
    }

    /**
     * Creates a new instance of estadistica
     */
    public estadistica() {
        FacesContext context = FacesContext.getCurrentInstance();
        if (context != null) {
            bean = (ProductoSeleccionadoBean) context.getApplication().
                    evaluateExpressionGet(context, "#{productoSeleccionadoBean}", ProductoSeleccionadoBean.class);
            productoId = bean.getProductoActual();
            sprintId = bean.getSprintActual();
            inicializarEstadisticas();
        }        
    }
    
    public final void inicializarEstadisticas() {
        List<Esfuerzo> esfuerzos = esfuerzoFacade.findAll();
        //Lista de tareas del SPrint actual
        log.log(Level.INFO, "Producto actual: {0}", productoId);
        log.log(Level.INFO, "Sprint actual: {0}", sprintId);
        List<Tarea> tareas = tareaFacade.findByProyectoAndSprint(productoId, sprintId);
        List<Tarea> tareasActuales = new ArrayList<Tarea>();
        List<Esfuerzo> esfuerzosActuales = new ArrayList<Esfuerzo>();
        duracion = fechasDiferenciaEnDias(sprintFacade.findById(sprintId).getFecini(), sprintFacade.
                findById(sprintId).getFecfin());
        log.log(Level.INFO, "Duracion= {0}", duracion);
        int parcial = 0;
        int restante = 0;
        actual = new int[(duracion + 1)];
        estimado = new int[duracion + 1];
        int actual1[] = new int[(duracion + 1)];

        todo = 0;
        doing = 0;
        done = 0;

        List<Colaborador> colaboradores = colaboradorFacade.findAll();
        int valor[] = null;

        if (tareas == null) {
            tareas = new ArrayList<Tarea>();
        }

        //----------------------Filtrado por tareas-----------------------------
        for (Tarea t : tareas) {
            for (Esfuerzo e : esfuerzos) {
                if (t.equals(e.getIdTareaFk())) {
                    //El esfuerzo pertenece a esta tarea
                    esfuerzosActuales.add(e);
                }
            }
            //Tenemos la lista de esfuerzos por tarea
            parcial = 0;
            restante = t.getEsf() * 100;
            if (t.getFecini() != null) {
                for (Esfuerzo e1 : esfuerzosActuales) {
                    //Caso de que sea la ultima fecha y la tarea este acabada 
                    //se toma como que esfuerzo realizado es igual al restante
                    //y se acaba la tarea
                    //if ((t.getFecfin() != null) && (t.getFecfin().equals(e1.getFec()))) {
                    if ((t.getFecfin() != null) && (t.getFecfin().equals(e1.getFec()))) {
                        parcial = (int) (e1.getDuracion() * 100);
                        restante = 0;
                    } else {
                        //Cualquier otro caso que no sea ni la fecha ultima ni 
                        //la primera fecha parcial=restante-(int) (e1.getDuracion() * 100);
                        parcial = restante - (int) (e1.getDuracion() * 100);
                        restante -= parcial;
                    }
                    log.log(Level.INFO, "Añado a actual en la posicion {0} un valor {1} por la tarea {2}",
                            new Object[]{
                                fechasDiferenciaEnDias(sprintFacade.findById(sprintId).
                                getFecini(), e1.getFec()),
                                parcial,
                                t.getId()
                            });
                    actual1[fechasDiferenciaEnDias(sprintFacade.findById(sprintId).
                            getFecini(), e1.getFec())] +=
                            parcial;
                }
            }
            esfuerzosActuales.clear();
            totalEsfuerzo += t.getEsf() * 100;

            //Estadistica sobre el estado de las tareas
            if (t.getIdEstadoFk().getId() == 1) {
                todo++;
            } else {
                if (t.getIdEstadoFk().getId() == 2) {
                    doing++;
                } else {
                    done++;
                }
            }

            //Estadistica sobre estado de tareas por colaborador
            /*
             * for (Colaborador c : colaboradores) { mapaColaboradores.put(c.getNombre(), new
             * int[]{0,0,0}); if (c.getTareaCollection().contains(t)) { valor =
             * mapaColaboradores.get(c.getNombre()); if (t.getFecfin() == null) { valor[0]++; } else
             * { if (t.getFecfin() == null) { valor[1]++; } else { valor[2]++; } }
             * mapaColaboradores.put(c.getNombre(), valor); } }
             */
        }
        log.log(Level.INFO, "Añado a actual en la posicion 0 un valor {0}", totalEsfuerzo);
        actual[0] = totalEsfuerzo;
        estimado[0] = totalEsfuerzo;
        relacion = totalEsfuerzo / duracion;
        for (int j = 1; j <= duracion; j++) {
            estimado[j] = estimado[j - 1] - relacion;
            actual[j] = actual[j - 1] - actual1[j];
            //log.log(Level.WARNING, "Actual {0} es {1} - {2} = {3}", new Object[]{j, actual[j - 1], actual1[j], actual[j]});
        }

        //Creamos toda la estadistica por colaborador
        for (Colaborador c : colaboradores) {
            log.log(Level.INFO, "Proceso el colaborador {0}", c.getNombre());
            mapaColaboradores.put(c.getNombre(), new int[]{0, 0, 0});
            valor = new int[]{0, 0, 0};
            for (Tarea t : c.getTareaCollection()) {
                valor = mapaColaboradores.get(c.getNombre());
                if (tareas.contains(t)) {
                    if (t.getIdEstadoFk().getId() == 1) {
                        valor[0]++;
                    } else {
                        if (t.getIdEstadoFk().getId() == 2) {
                            valor[1]++;
                        } else {
                            valor[2]++;
                        }
                    }
                }
            }
            log.log(Level.INFO, "y valores {0},{1},{2}", new Object[]{valor[0], valor[1], valor[2]});
            mapaColaboradores.put(c.getNombre(), valor);
        }
    }

    private static int fechasDiferenciaEnDias(Date fechaInicial, Date fechaFinal) {

        DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
        String fechaInicioString = df.format(fechaInicial);
        try {
            fechaInicial = df.parse(fechaInicioString);
        } catch (ParseException ex) {
        }

        String fechaFinalString = df.format(fechaFinal);
        try {
            fechaFinal = df.parse(fechaFinalString);
        } catch (ParseException ex) {
        }

        long fechaInicialMs = fechaInicial.getTime();
        long fechaFinalMs = fechaFinal.getTime();
        long diferencia = fechaFinalMs - fechaInicialMs;
        double dias = Math.floor(diferencia / (1000 * 60 * 60 * 24));
        return ((int) dias);
    }

    private SprintFacade lookupSprintFacade() {
        try {
            Context c = new InitialContext();
            return (SprintFacade) c.lookup("java:global/ScrumPMT/ScrumPMT-ejb/SprintFacade!org.scrumpmt.ejb.SprintFacade");
        } catch (NamingException ne) {
            log.log(Level.SEVERE, "exception caught", ne);
            throw new RuntimeException(ne);
        }
    }

    private TareaFacade lookupTareaFacade() {
        try {
            Context c = new InitialContext();
            return (TareaFacade) c.lookup("java:global/ScrumPMT/ScrumPMT-ejb/TareaFacade!org.scrumpmt.ejb.TareaFacade");
        } catch (NamingException ne) {
            log.log(Level.SEVERE, "exception caught", ne);
            throw new RuntimeException(ne);
        }
    }

    private EsfuerzoFacade lookupEsfuerzoFacade() {
        try {
            Context c = new InitialContext();
            return (EsfuerzoFacade) c.lookup("java:global/ScrumPMT/ScrumPMT-ejb/EsfuerzoFacade!org.scrumpmt.ejb.EsfuerzoFacade");
        } catch (NamingException ne) {
            log.log(Level.SEVERE, "exception caught", ne);
            throw new RuntimeException(ne);
        }
    }

    private ColaboradorFacade lookupColaboradorFacade() {
        try {
            Context c = new InitialContext();
            return (ColaboradorFacade) c.lookup("java:global/ScrumPMT/ScrumPMT-ejb/ColaboradorFacade!org.scrumpmt.ejb.ColaboradorFacade");
        } catch (NamingException ne) {
            log.log(Level.SEVERE, "exception caught", ne);
            throw new RuntimeException(ne);
        }
    }

    private boolean isPrimera(Esfuerzo e1, List<Esfuerzo> esfuerzosActuales) {
        for (Esfuerzo e : esfuerzosActuales) {
            if (fechasDiferenciaEnDias(e.getFec(), e1.getFec()) < 0) {
                return false;
            }
        }
        return true;
    }

    public ProductoSeleccionadoBean getBean() {
        return bean;
    }

    public void setBean(ProductoSeleccionadoBean bean) {
        this.bean = bean;
    }
}
